/*****************************************************************
 *   Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 ****************************************************************/
package org.epiphron.convert;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.logging.Logger;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;

import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.vocab.OWL2Datatype;

public class ConversionUtil {
	public static Logger LOGGER = Logger.getLogger("org.epiphron");
	
	public static String last(String path) {
		return end(path, '/');
	}
	
	private static String end(String s, char c) {
		int i = s.lastIndexOf(c);
		return (i > 0) ? s.substring(i+1) : s;
	}

    public static String getRdfType(Class<?> c) {
        RdfType rdfType = c.getAnnotation(RdfType.class);
        return (rdfType != null) ? rdfType.value(): c.getSimpleName();
    }

	public static Field[] getDeclaredFields(Class<?> c) {
		ArrayList<Field> fields = new ArrayList<Field>();
		for (Field field : c.getDeclaredFields())
			add(fields, field);
		Class<?> cls = c;
		while (cls.getSuperclass() != Object.class && cls.getSuperclass() != null) {
			cls = cls.getSuperclass();
			for (Field field : cls.getDeclaredFields())
				add(fields,field);
		}
		return fields.toArray(new Field[0]);
	}

	private static void add(ArrayList<Field> fields, Field field) {
		fields.add(field);
	}
	
	/**
	 * Converts Java value to given type literal
	 */
	public static OWLLiteral toLiteral(OWLDataFactory dataFactory, OWLDatatype range, Object o) {
		if (range != null) {
			if (o != null) {
				String value;
				
				if (o instanceof Date) {
					value = dateToXSDString(((Date) o).getTime());
				}
				else if (o instanceof Calendar) {
					value = dateToXSDString(((Calendar) o).getTimeInMillis());
				}
				else {
					value = o.toString();
				}
				
				return dataFactory.getOWLLiteral(value, range);
			}
		}
		else {
			// we guess type of literal automatically
			
			if (o instanceof String) {
				return dataFactory.getOWLLiteral(o.toString());
			}
			else if (o instanceof Integer) {
				return dataFactory.getOWLLiteral((Integer) o);
			}
			else if (o instanceof Double) {
				return dataFactory.getOWLLiteral((Double) o);
			}
			else if (o instanceof BigInteger) {
				return dataFactory.getOWLLiteral(((BigInteger) o).doubleValue());
			}
			else if (o instanceof BigDecimal) {
				return dataFactory.getOWLLiteral(((BigDecimal) o).doubleValue());
			}
			else if (o instanceof Float) {
				return dataFactory.getOWLLiteral((Float) o);
			}
			else if (o instanceof Boolean) {
				return dataFactory.getOWLLiteral((Boolean) o);
			}
			else if (o instanceof Date) {
				return getDateLiteral(dataFactory, ((Date) o).getTime());
			}
			else if (o instanceof Calendar) {
				return getDateLiteral(dataFactory, ((Calendar) o).getTimeInMillis());
			}
			else if (o instanceof Enum<?>) {
				return dataFactory.getOWLLiteral(o.toString());
			}
		}
		return null;
	}
	
	/**
	 * Converts date (by given time in millis) to XSD-style date
	 */
	private static String dateToXSDString(long time) {
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTimeInMillis(time);
		try {
			return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal).toXMLFormat();
		} catch (DatatypeConfigurationException e) {
			// should not happen
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * Creates OWL dateTime literal
	 */
	public static OWLLiteral getDateLiteral(OWLDataFactory dataFactory, long time) {
		return dataFactory.getOWLLiteral(
				dateToXSDString(time),
				OWL2Datatype.XSD_DATE_TIME);
	}
}
